/*===========================================================================
  Copyright (C) 2014 by the Okapi Framework contributors
-----------------------------------------------------------------------------
  This library is free software; you can redistribute it and/or modify it 
  under the terms of the GNU Lesser General Public License as published by 
  the Free Software Foundation; either version 2.1 of the License, or (at 
  your option) any later version.

  This library is distributed in the hope that it will be useful, but 
  WITHOUT ANY WARRANTY; without even the implied warranty of 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
  General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License 
  along with this library; if not, write to the Free Software Foundation, 
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

  See also the full LGPL text here: http://www.gnu.org/copyleft/lesser.html
===========================================================================*/

package net.sf.okapi.applications.lynxweb;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.okapi.lib.xliff2.Util;
import net.sf.okapi.lib.xliff2.core.Unit;
import net.sf.okapi.lib.xliff2.reader.Event;
import net.sf.okapi.lib.xliff2.reader.EventType;
import net.sf.okapi.lib.xliff2.reader.XLIFFReader;
import net.sf.okapi.lib.xliff2.validation.Issue;
import net.sf.okapi.lib.xliff2.validation.Validation;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.apache.commons.io.input.BOMInputStream;

@SuppressWarnings("serial")
public class XLIFFValidation extends HttpServlet
{
	static private String HEAD = Html.HEAD1+"XLIFF 2 Validation"+Html.HEAD2;
	
	static private String FORMPART1 = "<form action='/validation' accept-charset='UTF-8' method='POST' enctype='multipart/form-data'>"
		+ "<input name='mark' type='hidden' value='&#x2620;' />"
       	+ "<input style='font-weight:bold;padding:.5em' type='submit' value='Validate the Selected XLIFF 2 Document' />&nbsp;&nbsp;"
		+ "<input type='checkbox' name='doValRules' ";
	
	static private String FORMPART2 = ">Process the rules of <a href='http://docs.oasis-open.org/xliff/xliff-core/v2.0/xliff-core-v2.0.html#validation_module'>the Validation module</a> too<br />"
       	+ "<input type='radio' name='type' value='type' id='typeF' onclick=\"document.getElementById('file').disabled=false;document.getElementById('content').disabled=true;\">"
       	+ "<label for='typeF'>Upload the document to process.</label><br />"
       	+ "<input type='file' id='file' name='file' disabled /><br />"
       	+ "<input type='radio' name='type' value='type' id='typeC' checked onclick=\"document.getElementById('content').disabled=false;document.getElementById('file').disabled=true;\">"
       	+ "<label for='typeC'>Enter the content to process.</lable><br />"
       	+ "<textarea rows='30' cols='100' id='content' name='content'>";
		
	static private String FORMPART3 = "</textarea>"
       	+ "</form>";
			
	static private String DEFCODE = "<xliff xmlns='urn:oasis:names:tc:xliff:document:2.0' version='2.0'\n"
		+ " srcLang='en' trgLang='fr'>\n"
		+ " <file id='1'>\n"
		+ "  <val:validation xmlns:val='urn:oasis:names:tc:xliff:validation:2.0'>\n"
		+ "   <val:rule startsWith='*'/>\n"
		+ "  </val:validation>\n"
		+ "  <unit id='1'>\n"
		+ "   <originalData>\n"
		+ "    <data id='d1'>&lt;B></data>\n"
		+ "    <data id='d2'>&lt;/B></data>\n"
		+ "   </originalData>\n"
		+ "   <segment>\n"
		+ "    <source>* Hello <pc id='1' dataRefStart='d1' dataRefEnd='d2' type='fmt' subType='xlf:b'>World</pc>! </source>\n"
		+ "    <target>* Bonjour <pc id='1' dataRefStart='d1' dataRefEnd='d2' type='fmt' subType='xlf:b'>tout le monde</pc>\u00A0! </target>\n"
		+ "   </segment>\n"
		+ "   <segment>\n"
		+ "    <source>Welcome in the universe of <pc id='2' dataRefStart='d1' dataRefEnd='d2' type='fmt' subType='xlf:b'>XLIFF 2</pc>.</source>\n"
		+ "   </segment>\n"
		+ "  </unit>\n"
		+ " </file>\n"
		+ "</xliff>";

	@Override
    public void doGet (HttpServletRequest req,
    	HttpServletResponse resp)
    	throws ServletException, IOException
    {
		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println(HEAD);
        resp.getWriter().println(FORMPART1+"checked"+FORMPART2+Util.toXML(DEFCODE, false)+FORMPART3);
        resp.getWriter().println(Html.INFO);
    }

	@Override
    public void doPost (HttpServletRequest req,
    	HttpServletResponse resp)
    	throws ServletException, IOException
    {
		String content = "";
		boolean doValRules = false;
		String resValRules = null;
		String result = null;
		try {
			ServletFileUpload sfup = new ServletFileUpload(new DiskFileItemFactory());
			sfup.setFileSizeMax(Html.FILESIZEMAX);
			sfup.setSizeMax(Html.SIZEMAX);
			
			FileItemIterator iterator = sfup.getItemIterator(req);
			while ( iterator.hasNext() ) {
		        FileItemStream item = iterator.next();
		        InputStream stream = item.openStream();
		        if ( item.isFormField() ) {
		        	// Process regular form field
		        	if ( item.getFieldName().equals("content") ) {
		        		content = Streams.asString(stream, "UTF-8");
		        		
		        	}
		        	else if ( item.getFieldName().equals("doValRules") ) {
		        		doValRules = true;
		        	}
		        }
		        else { // For files, make sure to deal with the BOM
		        	content = Streams.asString(new BOMInputStream(stream), "UTF-8");
		        }
			}

			result = "<p style='background-color:green;color:white;padding:.5em;"
				+ (doValRules ? "margin-bottom:1" : "")
				+ "'>The document is VALID.</p>";
			// Validate the document
			XLIFFReader.validate(content, null);
			// Check the Validation module if requested
			if ( doValRules ) {
				// return null if no rules detected, empty if no error
				List<Issue> list = processValidationRules(content);
				if ( list == null ) {
					resValRules = "<p style='background-color:lightgray;color:black;padding:.5em;margin-top:0'>The document does not use the Validation module.</p>";
				}
				else if ( list.isEmpty() ) {
					resValRules = "<p style='background-color:green;color:white;padding:.5em;margin-top:0'>No issue detected in the Validation rules.</p>";
				}
				else {
					resValRules = "<p style='background-color:red;color:white;padding:.5em;margin-top:0'>One issue or more detected in the Validation rules:</p>";
					StringBuilder tmp = new StringBuilder("<pre>");
					for ( Issue issue : list ) {
						tmp.append("-- File-ID="+issue.getFileId()+", unit-ID="+issue.getUnitId()
							+": "+Util.toXML(issue.getCode(), false)+ "\n   ");
						tmp.append("Rule: "+issue.getRuleInfo()+"\n   ");
						tmp.append(Util.toXML(issue.getText(), false)+"\n");
					}
					tmp.append("</pre>");
					resValRules += tmp.toString();
				}
			}
		}
		catch ( Throwable e ) {
//			StringWriter sw = new StringWriter();
//			PrintWriter pw = new PrintWriter(sw);
//			e.printStackTrace(pw);
//			result = "<p style='background-color:red;color:white;padding:.5em'>ERROR DETECTED:</p><pre>"
//				+Util.toXML(sw.toString(), false)+"</pre>";
//			result += "<pre>"+Util.toXML(content, false)+"</pre>";
			result = "<p style='background-color:red;color:white;padding:.5em'>ERROR DETECTED:</p><pre>"
				+Util.toXML(e.getLocalizedMessage(), false)+"</pre>";
		}

		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html;charset=UTF-8");
		resp.getWriter().println(HEAD);
		resp.getWriter().println(result);
		if ( resValRules != null ) resp.getWriter().println(resValRules);
		resp.getWriter().println(FORMPART1
			+ (doValRules ? "checked" : "") + FORMPART2 
			+ Util.toXML(content, false) + FORMPART3);
		resp.getWriter().println(Html.INFO);
    }
	
	/**
	 * Process the content for validation rules.
	 * @param content the content
	 * @return null if no rules have been found, a list of 0 or more issue otherwise.
	 */
	private List<Issue> processValidationRules (String content) {
		List<Issue> allIssues = null;
		// No need to do maximum validation, it was done already
		try ( XLIFFReader reader = new XLIFFReader(XLIFFReader.VALIDATION_MINIMAL) ) {
			reader.open(content);
			String fileId = null;
			while ( reader.hasNext() ) {
				Event event = reader.next();
				if ( event.getType() == EventType.START_FILE ) {
					fileId = event.getStartFileData().getId();
				}
				else if ( event.getType() == EventType.TEXT_UNIT ) {
					Unit unit = event.getUnit();
					if ( !unit.hasValidation() ) continue;
					if ( allIssues == null ) {
						allIssues = new ArrayList<>();
					}
					Validation val = unit.getValidation();
					List<Issue> issues = val.processRules(unit, fileId);
					if ( issues == null ) continue;
					allIssues.addAll(issues);
				}
			}
		}
		return allIssues;
	}

}
